//学习信号的内容：
#include<iostream>
#include<string>
#include<cstdlib>
#include<unistd.h>
#include<signal.h>
#include<sys/types.h>
using namespace std;
//学习信号之前的知识补充：
//AB看到同一份资源时，如果不加以保护，会导致数据不一致的问题
//加锁：互斥访问：任何时刻，只允许一个执行流访问共享资源
//共享的，任何时刻只允许一个执行流访问的资源叫做：临界资源
//我们访问临界资源的代码叫作临界区

//大部分信号都是有快捷键的，ctrl+c是2号信号的快捷键

//键盘能够直接给CPU通过硬件中断的方式发送信号给CPU，让CPU检查键盘的输入

//信号量机制：就是使用一个计数器去统计临界资源的个数，每个执行流想要访问或者使用这个临济资源之前先要申请一个计数器资源，此时信号量-1，当信号量到0的时候就表示没有剩余可用的临界资源需要等待其他执行流使用完成

//进程必须能够识别信号，这是进程内置功能的一种

//前台进程和后台进程：
/*
终端交互：
前台进程：与终端直接交互，可以接收用户的输入并显示输出到终端。用户必须等待前台进程完成才能在同一个终端上执行其他命令。
后台进程：与终端没有直接交互，它们在后台运行，不会阻塞用户在终端上执行其他命令。后台进程的输出通常不会显示在终端上，除非特别指定。

终端关闭时的行为：
前台进程：当用户关闭终端时，前台进程通常会被终止。这是因为终端提供了进程的标准输入、输出和错误流。
后台进程：当用户关闭终端时，后台进程不会自动终止，它们会继续在后台运行，直到完成或被显式终止。

控制方式：
前台进程：可以通过终端直接控制，如使用Ctrl+C来中断进程。
后台进程：不能直接通过终端控制，需要使用特定的命令（如kill）来发送信号。
*/
//把一个程序放置在后台执行只需要加上&  例如： ./sig &
//linux中，应该终端只会配上一个bash，只允许一个进程是前台进程，允许多个后台进程

void Usage(string proc)
{
    //提醒用户使用格式
    cout<<"Usage:\n\t"<<proc<<"signum pid\n\n";
}

//命令行参数，argc是argv中元素个数，argv[0]是命令名字，argv[1]以及之后的是后面的参数
//例如：./sig -a -b 1,那么agrv[0]是"./sig" argv[1]是"-a"以此类推
//注意命令行参数都是以字符指针的方式存储在argv中（也就是字符串的形式）
int main(int argc,char* argv[])
{
    if(argc!=3)//也就是强制我们想要执行必须命令行参数个数为3
    {
        Usage(argv[0]);
        exit(1);
    }
    //我们规定了使用规则：程序名称，信号序号，pid
    int signum=stoi(argv[1]);
    pid_t pid=stoi(argv[2]);

    //系统调用kill函数（pid，signum）允许向pid进程发送一个signum信号  这和终端中输入kill -2 22456的指令功能一样，都是给进程发送信号
    int n=kill(pid,signum);//例如可以控制这个进程用来杀死其他进程，例如：./sig 2 22456就是执行这个程序给22456号进程发送一个2号信号
    if(n==-1)//失败返回-1
    {
        perror("kill");
        exit(2);
    }
    return 0;

}
//小结：信号的产生方式有很多种：代码段错误，进程的等待，进程给进程发送信号，通过终端发送信号，键盘发送信号，系统调用函数kill，raise等

//IPC资源：IPC资源指的是进程间通信（Inter-Process Communication，简称IPC）的资源，它包括共享内存、消息队列和信号量这三种主要的进程间通信机制
//IPC在内核中的数据结构设计：所有的IPC资源都是统一放在一个IPC结构体指针数组之中的
//那么共享内存和消息队列这些IPC资源怎么统一放在同一个结构体指针数组之中呢？
//就是把所有的结构体的第一个成员都固定为ipc_perm结构体，保存这些ipc资源的时候只需要把这些结构体的ipc_perm结构体地址存放在ipc_perm结构体指针数组之中，要使用某个结构体的时候就按照对应结构的指针去强转一下即可，例如如果要共享内存的资源：(sruct shmid_ds*)addr就可以操作整个共享内存的结构体了
//并且：由于所有的ipc资源结构体第一个成员都是ipc_perm结构体，所以这也涉及到继承的关系，基类有这个结构体，所有的ipc子类都继承这个ipc_perm结构体就可以了



//system V：
//扩展：消息队列：也是进程间通信的一种方式，他们发送给对方的数据以数据块的方式发送，并且将数据先放在一个存储消息块的队列之中，进程要对应的数据就自己去队列中取目标数据即可
